package cn.xwt.weidisk.service.impl;

import cn.xwt.weidisk.constant.ServiceError;
import cn.xwt.weidisk.mapper.LoginLogMapper;
import cn.xwt.weidisk.mapper.UserMapper;
import cn.xwt.weidisk.pojo.dao.LoginLogDo;
import cn.xwt.weidisk.pojo.dao.UserDo;
import cn.xwt.weidisk.pojo.dto.*;
import cn.xwt.weidisk.service.UserService;
import cn.xwt.weidisk.util.CosUtils;
import cn.xwt.weidisk.util.RedisUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Base64Utils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.util.Collections;
import java.util.List;
import java.util.UUID;

/**
 * @author 薛慰涛
 */
@Service("userService")
public class UserServiceImpl implements UserService {

    @Resource
    UserMapper userMapper;
    @Resource
    RedisUtils redisUtils;
    @Resource
    BCryptPasswordEncoder passwordEncoder;
    @Resource
    LoginLogMapper loginLogMapper;
    @Resource
    RestTemplate restTemplate;

    @Override
    public UserDetails loadUserByUsername(String value) throws UsernameNotFoundException {
        UserDo userDo = userMapper.selectUserByEmailOrUsername(value);
        if (null == userDo) {
            throw new UsernameNotFoundException("用户不存在");
        }
        return userDo;
    }

    @Override
    public boolean existsUsername(String username) {
        Long id = userMapper.selectUserId(username, null);
        return id != null;
    }

    @Override
    public boolean existsEmail(String email) {
        Long id = userMapper.selectUserId(null, email);
        return id != null;
    }

    @Override
    public ServiceError registerUser(RegData regData) {
        // 获取输入的验证码
        String reqCode = regData.getVerificationCode();
        // 获取后删除redis中的验证码
        String redisCode = redisUtils.get(regData.getEmail());
        // 验证码错误
        if(!reqCode.equals(redisCode)) {
            return  ServiceError.CODE_ERROR;
        }
        redisUtils.del(regData.getEmail());
        // 用户名已存在
        if (existsUsername(regData.getUsername())) {
            return ServiceError.USERNAME_EXISTS;
        }
        // 邮箱已存在
        if (existsEmail(regData.getEmail())) {
            return ServiceError.EMAIL_EXISTS;
        }
        // 密码加密
        String password = passwordEncoder.encode(regData.getPassword());
        // 注册
        UserDo regUserDo = new UserDo();
        regUserDo.setUsername(regData.getUsername());
        regUserDo.setEmail(regData.getEmail());
        regUserDo.setPassword(password);
        regUserDo.setRole("ROLE_user");
        regUserDo.setLocked((byte)0);
        regUserDo.setCapacity(1);
        if (userMapper.insertUser(regUserDo) == 1) {
            return ServiceError.SUCCESS;
        } else {
            return ServiceError.ERROR;
        }
    }

    @Override
    public UserData selectUser(Long id) {
        UserDo user = userMapper.selectUser(id);
        UserData userData = new UserData();
        userData.setUsername(user.getUsername());
        userData.setEmail(user.getEmail());
        return userData;
    }

    @Override
    public boolean saveAvatar(String avatarData, Long id) {
        // 头像文件后缀
        final String suffix = ".jpg";
        final int two = 2;
        try {
            String data;
            // 获取base64数据
            if(avatarData == null || "".equals(avatarData)){
                throw new Exception("上传失败，上传图片数据为空");
            }else{
                String [] d = avatarData.split("base64,");
                if(d.length == two){
                    data = d[1];
                }else{
                    throw new Exception("上传失败，数据不合法");
                }
            }
            // 定义头像键
            String existAvatarName = userMapper.selectAvatar(id);
            String avatarName;
            // 如果是第一次上传头像则生成新的头像键，否则使用已存在的头像键
            if (existAvatarName == null) {
                avatarName = UUID.randomUUID().toString().replace("-", "") + suffix;
                // 将头像键保存到user表中
                userMapper.updateAvatar(id, avatarName);
            } else {
                avatarName = existAvatarName;
            }
            // 将头像读取为输入流
            byte[] bs = Base64Utils.decodeFromString(data);
            ByteArrayInputStream is = new ByteArrayInputStream(bs);
            // 保存头像到cos
            CosUtils.uploadAvatar(is, avatarName);
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    @Override
    public String getAvatarLink(Long id) {
        final String defaultAvatar = "https://weidisk-avatar-1301502838.cos.ap-guangzhou.myqcloud.com/wei.jpg";
        String avatar = userMapper.selectAvatar(id);
        return avatar == null ? defaultAvatar : CosUtils.getAvatarLink(avatar);
    }

    @Override
    public ServiceError updateUsername(UsernameData usernameData) {
        String code = redisUtils.get(usernameData.getEmail());
        // 验证码错误
        if (code == null || !code.equals(usernameData.getCode())) {
            return ServiceError.CODE_ERROR;
        }
        redisUtils.del(usernameData.getEmail());
        // 用户名已存在
        if (existsUsername(usernameData.getUsername())) {
            return ServiceError.USERNAME_EXISTS;
        }
        userMapper.updateUsername(usernameData.getId(), usernameData.getUsername());
        return ServiceError.SUCCESS;
    }

    @Override
    public Boolean updatePassword(PasswordData passwordData) {
        String code = redisUtils.get(passwordData.getEmail());
        if (code != null && code.equals(passwordData.getCode())) {
            userMapper.updatePassword(passwordData.getId(), passwordEncoder.encode(passwordData.getPassword()));
            redisUtils.del(passwordData.getEmail());
            return true;
        } else {
            return false;
        }
    }

    @Override
    public ServiceError updateEmail(EmailData emailData) {
        String code = redisUtils.get(emailData.getEmail());
        if (code != null && code.equals(emailData.getCode())) {
            redisUtils.del(emailData.getEmail());
            String password = userMapper.selectPassword(emailData.getId());
            if (passwordEncoder.matches(emailData.getPassword(), password)) {
                userMapper.updateEmail(emailData.getId(), emailData.getEmail());
                return ServiceError.SUCCESS;
            } else {
                return ServiceError.PASSWORD_ERROR;
            }
        } else {
            return ServiceError.CODE_ERROR;
        }
    }

    @Override
    public Integer getCapacity(Long id) {
        return userMapper.selectCapacity(id) * 1024;
    }

    @Override
    public List<UserDo> getUserList() {
        return userMapper.selectUserList();
    }

    @Override
    public void updateLocked(Long id, Byte locked) {
        userMapper.updateLocked(id, locked);
    }

    @Override
    public void updateCapacity(Long id, Integer capacity) {
        userMapper.updateCapacity(id, capacity);
    }

    @Override
    public void saveLoginLog(Long uid, String type, String ip) {
        String url = "https://apis.map.qq.com/ws/location/v1/ip?ip={1}&key={2}";
        String key = "KI6BZ-DFM3O-CLFW2-SDFRG-JGEOF-3VFJJ";
        LocationData result = restTemplate.getForObject(url, LocationData.class, ip, key);
        loginLogMapper.insertLoginLog(uid, type, ip, result.getLocation());
    }

    @Override
    public List<LoginLogDo> selectLoginLogList(Long uid) {
        return loginLogMapper.selectLoginLogList(uid);
    }
}
